package gxwl.user.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import gxwl.common.utils.AESUtil;
import gxwl.common.utils.Constant;
import gxwl.exceptionhanlder.CommonException;
import gxwl.relation.enums.SysRelationCategoryEnum;
import gxwl.relation.param.SysUserGrantResourceParam;
import gxwl.relation.param.SysUserGrantRoleParam;
import gxwl.relation.service.SysRelationService;
import gxwl.user.enmus.AuthExceptionEnum;
import gxwl.user.enmus.SysUserStatusEnum;
import gxwl.user.entity.SysUser;
import gxwl.user.mapper.UserMapper;
import gxwl.user.service.SysUserService;
import gxwl.user.vo.AuthAccountPasswordLoginParam;
import gxwl.user.vo.SysUserAddParam;
import gxwl.user.vo.SysUserEditParam;
import gxwl.user.vo.SysUserIdParam;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class SysUserServiceImpl extends ServiceImpl<UserMapper, SysUser> implements SysUserService {
    private final SysRelationService sysRelationService;
    @Override
    @SneakyThrows
    public String doLogin(AuthAccountPasswordLoginParam authAccountPasswordLoginParam) {
        // 获取账号
        String account = authAccountPasswordLoginParam.getAccount();
        // 获取密码
        String password = authAccountPasswordLoginParam.getPassword();
        SysUser sysUser = this.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getAccount, account));
        if (ObjectUtil.isNotEmpty(sysUser)) {
            throw new CommonException(AuthExceptionEnum.ACCOUNT_ERROR.getValue());
        }
        if (!authAccountPasswordLoginParam.getPassword().equals(password)) {
            throw new CommonException(AuthExceptionEnum.PWD_ERROR.getValue());
        }
        if(!SysUserStatusEnum.ENABLE.getValue().equals(sysUser.getUserStatus())){
            throw new CommonException(AuthExceptionEnum.ACCOUNT_DISABLED.getValue());
        }
        // 执行登录
        StpUtil.login(sysUser.getId(), new SaLoginModel().setExtra("name", sysUser.getName()));
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysUserAddParam sysUserAddParam) {
        // 输入信息校验
        checkParam(sysUserAddParam);
        SysUser sysUser = BeanUtil.toBean(sysUserAddParam, SysUser.class);
        // 设置默认密码
        sysUser.setPassword(AESUtil.aesEncrypt(sysUserAddParam.getPassword()));
        // 设置状态
        sysUser.setUserStatus(SysUserStatusEnum.ENABLE.getValue());
        this.save(sysUser);
    }

    @Override
    public void edit(SysUserEditParam sysUserEditParam) {
        SysUser sysUser = this.getById(sysUserEditParam.getId());
        if (ObjectUtil.isEmpty(sysUser)) {
            throw new CommonException("用户不存在，id值为：{}", sysUserEditParam.getId());
        }
        checkParam(sysUserEditParam);
        // 为null的不更新，有值的以新值为准（空的还是会更新）
        BeanUtil.copyProperties(sysUserEditParam, sysUser, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        this.updateById(sysUser);
    }

    @Override
    public void delete(List<SysUserIdParam> sysUserIdParamList) {
        List<String> sysUserIdList = CollStreamUtil.toList(sysUserIdParamList, SysUserIdParam::getId);
        this.removeByIds(sysUserIdList);
    }

    @Override
    public void disableUser(SysUserIdParam sysUserIdParam) {
        this.update(new LambdaUpdateWrapper<SysUser>().eq(SysUser::getId,
                sysUserIdParam.getId()).set(SysUser::getUserStatus, SysUserStatusEnum.DISABLED.getValue()));
    }

    @Override
    public void enableUser(SysUserIdParam sysUserIdParam) {
        this.update(new LambdaUpdateWrapper<SysUser>().eq(SysUser::getId,
                sysUserIdParam.getId()).set(SysUser::getUserStatus, SysUserStatusEnum.ENABLE.getValue()));
    }

    @Override
    public void resetPassword(SysUserIdParam sysUserIdParam) {
        this.update(new LambdaUpdateWrapper<SysUser>().eq(SysUser::getId,sysUserIdParam.getId()).
                set(SysUser::getPassword, AESUtil.aesEncrypt(Constant.REST_PASSWORD)));
    }

    @Override
    public List<String> ownRole(SysUserIdParam sysUserIdParam) {
        return sysRelationService.getRelationTargetIdListByObjectIdAndCategory(sysUserIdParam.getId(),
                SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue());
    }

    @Override
    public void grantRole(SysUserGrantRoleParam sysUserGrantRoleParam) {
        sysRelationService.saveRelationBatchWithClear(sysUserGrantRoleParam.getId(), sysUserGrantRoleParam.getRoleIdList(),
                SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue());
    }

    @Override
    public void grantResource(SysUserGrantResourceParam sysUserGrantResourceParam) {
        List<String> menuIdList = sysUserGrantResourceParam.getGrantInfoList().stream()
                .map(SysUserGrantResourceParam.SysUserGrantResource::getMenuId).collect(Collectors.toList());
        List<String> extJsonList = sysUserGrantResourceParam.getGrantInfoList().stream()
                .map(JSONUtil::toJsonStr).collect(Collectors.toList());
        sysRelationService.saveRelationBatchWithClear(sysUserGrantResourceParam.getId(), menuIdList, SysRelationCategoryEnum.SYS_USER_HAS_RESOURCE.getValue(), extJsonList);
    }

    private void checkParam(SysUserAddParam sysUserAddParam) {
        if (ObjectUtil.isNotEmpty(sysUserAddParam.getAccount())) {
            if (this.count(new LambdaQueryWrapper<SysUser>()
                    .eq(SysUser::getAccount, sysUserAddParam.getAccount())) > 0) {
                throw new CommonException("存在重复的账号，账号为：{}", sysUserAddParam.getAccount());
            }
        }
        if (ObjectUtil.isNotEmpty(sysUserAddParam.getPhone())) {
            if (!PhoneUtil.isMobile(sysUserAddParam.getPhone())) {
                throw new CommonException("手机号码：{}格式错误", sysUserAddParam.getPhone());
            }
            if (this.count(new LambdaQueryWrapper<SysUser>()
                    .eq(SysUser::getPhone, sysUserAddParam.getPhone())) > 0) {
                throw new CommonException("存在重复的手机号，手机号为：{}", sysUserAddParam.getPhone());
            }
        }
    }

    private void checkParam(SysUserEditParam sysUserEditParam) {
        if (ObjectUtil.isNotEmpty(sysUserEditParam.getPhone())) {
            if (!PhoneUtil.isMobile(sysUserEditParam.getPhone())) {
                throw new CommonException("手机号码：{}格式错误", sysUserEditParam.getPhone());
            }
            if (this.count(new LambdaQueryWrapper<SysUser>()
                    .eq(SysUser::getPhone, sysUserEditParam.getPhone())
                    .ne(SysUser::getId, sysUserEditParam.getId())) > 0) {
                throw new CommonException("存在重复的手机号，手机号为：{}", sysUserEditParam.getPhone());
            }
        }
    }
}
